/** @file
  OSTA Universal Disk Format (UDF) definitions.

  Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>

  SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#ifndef __UDF_H__
#define __UDF_H__

#define UDF_BEA_IDENTIFIER   "BEA01"
#define UDF_NSR2_IDENTIFIER  "NSR02"
#define UDF_NSR3_IDENTIFIER  "NSR03"
#define UDF_TEA_IDENTIFIER   "TEA01"

#define UDF_LOGICAL_SECTOR_SHIFT  11
#define UDF_LOGICAL_SECTOR_SIZE   ((UINT64)(1ULL << UDF_LOGICAL_SECTOR_SHIFT))
#define UDF_VRS_START_OFFSET      ((UINT64)(16ULL << UDF_LOGICAL_SECTOR_SHIFT))

typedef enum {
  UdfPrimaryVolumeDescriptor = 1,
  UdfAnchorVolumeDescriptorPointer = 2,
  UdfVolumeDescriptorPointer = 3,
  UdfImplemenationUseVolumeDescriptor = 4,
  UdfPartitionDescriptor = 5,
  UdfLogicalVolumeDescriptor = 6,
  UdfUnallocatedSpaceDescriptor = 7,
  UdfTerminatingDescriptor = 8,
  UdfLogicalVolumeIntegrityDescriptor = 9,
  UdfFileSetDescriptor = 256,
  UdfFileIdentifierDescriptor = 257,
  UdfAllocationExtentDescriptor = 258,
  UdfFileEntry = 261,
  UdfExtendedFileEntry = 266,
} UDF_VOLUME_DESCRIPTOR_ID;

#pragma pack(1)

typedef struct {
  UINT16  TagIdentifier;
  UINT16  DescriptorVersion;
  UINT8   TagChecksum;
  UINT8   Reserved;
  UINT16  TagSerialNumber;
  UINT16  DescriptorCRC;
  UINT16  DescriptorCRCLength;
  UINT32  TagLocation;
} UDF_DESCRIPTOR_TAG;

typedef struct {
  UINT32  ExtentLength;
  UINT32  ExtentLocation;
} UDF_EXTENT_AD;

typedef struct {
  UINT8           CharacterSetType;
  UINT8           CharacterSetInfo[63];
} UDF_CHAR_SPEC;

typedef struct {
  UINT8           Flags;
  UINT8           Identifier[23];
  union {
    //
    // Domain Entity Identifier
    //
    struct {
      UINT16      UdfRevision;
      UINT8       DomainFlags;
      UINT8       Reserved[5];
    } Domain;
    //
    // UDF Entity Identifier
    //
    struct {
      UINT16      UdfRevision;
      UINT8       OSClass;
      UINT8       OSIdentifier;
      UINT8       Reserved[4];
    } Entity;
    //
    // Implementation Entity Identifier
    //
    struct {
      UINT8       OSClass;
      UINT8       OSIdentifier;
      UINT8       ImplementationUseArea[6];
    } ImplementationEntity;
    //
    // Application Entity Identifier
    //
    struct {
      UINT8       ApplicationUseArea[8];
    } ApplicationEntity;
    //
    // Raw Identifier Suffix
    //
    struct {
      UINT8       Data[8];
    } Raw;
  } Suffix;
} UDF_ENTITY_ID;

typedef struct {
  UINT32        LogicalBlockNumber;
  UINT16        PartitionReferenceNumber;
} UDF_LB_ADDR;

typedef struct {
  UINT32                           ExtentLength;
  UDF_LB_ADDR                      ExtentLocation;
  UINT8                            ImplementationUse[6];
} UDF_LONG_ALLOCATION_DESCRIPTOR;

typedef struct {
  UDF_DESCRIPTOR_TAG  DescriptorTag;
  UDF_EXTENT_AD       MainVolumeDescriptorSequenceExtent;
  UDF_EXTENT_AD       ReserveVolumeDescriptorSequenceExtent;
  UINT8               Reserved[480];
} UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER;

typedef struct {
  UDF_DESCRIPTOR_TAG              DescriptorTag;
  UINT32                          VolumeDescriptorSequenceNumber;
  UDF_CHAR_SPEC                   DescriptorCharacterSet;
  UINT8                           LogicalVolumeIdentifier[128];
  UINT32                          LogicalBlockSize;
  UDF_ENTITY_ID                   DomainIdentifier;
  UDF_LONG_ALLOCATION_DESCRIPTOR  LogicalVolumeContentsUse;
  UINT32                          MapTableLength;
  UINT32                          NumberOfPartitionMaps;
  UDF_ENTITY_ID                   ImplementationIdentifier;
  UINT8                           ImplementationUse[128];
  UDF_EXTENT_AD                   IntegritySequenceExtent;
  UINT8                           PartitionMaps[6];
} UDF_LOGICAL_VOLUME_DESCRIPTOR;

#pragma pack()

#endif
